package com.xm.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xm.common.GoodsEnum;
import com.xm.common.ThreadPool;
import com.xm.common.constant.CommonConstant;
import com.xm.common.HttpSingleton;
import com.xm.common.constant.UrlConstant;
import com.xm.entity.*;
import com.xm.factory.service.ConfigurationFactory;
import com.xm.service.BuyXmGoodService;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.User;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * @Author tianqin
 * @Date 2024/7/26 15:56
 * 具体实现类
 */
@Service
@Slf4j
public class BuyXmGoodServiceImpl implements BuyXmGoodService {
    @Autowired
    private JavaMailSenderImpl mailSender;

    // 添加静态HashMap来跟踪任务
    private static final ConcurrentHashMap<String, Set<UserTaskInfo>> userTasks = new ConcurrentHashMap<>();

    // 主流程失败次数
    private static int retryCount = CommonConstant.ZERO;

    // 给前端获取
    public Map<String, Set<UserTaskInfo>> getAllUserRunningTask() {
//        return new HashMap<>(userTasks);
        return userTasks.entrySet().stream()
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        entry -> entry.getValue().stream()
                                .collect(Collectors.toMap(
                                        UserTaskInfo::getTaskId, // 按 taskId 去重
                                        task -> task,
                                        (oldTask, newTask) -> oldTask // 如果重复，保留旧值
                                ))
                                .values()
                                .stream()
                                .collect(Collectors.toSet())
                ));
    }

    /**
     * 业务主流程 真正执行业务的方法
     * @param userName
     * @param heartPrice
     */
    @Override
    public void buyXmDataOrder(String userName, String heartPrice,String goodName,String subType) {
        // 创建任务信息并存入map
        UserTaskInfo taskInfo = new UserTaskInfo(userName, heartPrice, goodName, subType);
        // 如果未获取，就默认创建一个集合，并且添加当前的任务信息到集合中去
        userTasks.computeIfAbsent(
                userName, k -> Collections.synchronizedSet(new HashSet<>(10))
                ).add(taskInfo);
        // 每当有请求重新进入，重置retry次数
        retryCount = CommonConstant.ZERO;
        // 获取用户配置
        UserEntity currentUserConfig = ConfigurationFactory.getImplByKey(userName);
        // 心理预期价格(最大值,只会显示出价格小于该值的商品)
        BigDecimal suitablePrice = new BigDecimal(heartPrice);
        // 异步处理结果容器
        List<Future<String>> futureList = new ArrayList<>();
        // 标识符(循环是否需要中止)
        AtomicBoolean taskIsNeedContinue = new AtomicBoolean(true);
        try {
            // 循环获取商品信息(当锁单成功或者重试三次后退出循环)
            while (taskIsNeedContinue.get() && retryCount < CommonConstant.MAX_RETRY){
                List<Long> productIds = this.getGoodsInfo(subType,taskInfo,suitablePrice);
                for (Long productId : productIds) {
                    // 并发进行锁单操作
                    Future<String> futureResult = ThreadPool.getPoolExecutor().submit(buildOrderTaskByCurrentUser(productId, currentUserConfig));
                    futureList.add(futureResult);
                }
                // 处理并发结果,判断是否需要中止流程
                checkFutureResults(futureList,taskIsNeedContinue);
            }
            // 标识符为false 发送邮件提示购买成功
            // 标识符为true 线程重试次数达到最大值
            if (!taskIsNeedContinue.get()){
                this.sendEmail(currentUserConfig,"Success Buy!!!");
            }else {
                this.sendEmail(currentUserConfig,"Max Retry,Please ReStart The Service~");
            }
        }catch (IOException e) {
            retryCount++;
            System.out.println("网络通信发生异常--->" + e);
            this.buyXmDataOrder(userName,heartPrice,goodName,subType);
        }catch (InterruptedException e) {
            System.out.println("主动中断业务流程--->" + e);
        }catch (Exception e){
            System.out.println("业务主流程发生异常--->" + e);
        }finally {
            // 如果任务结束，可以选择保留一段时间后移除，或者保留供查询
            userTasks.remove(userName); // 根据需求决定是否立即移除
        }
    }

    @PostConstruct
    private HashMap<String,String> getGoodsMap() throws IOException, InterruptedException {
        List<HotHomeEntity.Category> homeDataList = getHomeDataList();
        HashMap<String, String> homeDataMap = new HashMap<>();
        for (HotHomeEntity.Category datum : homeDataList) {
            List<HotHomeEntity.DataListItem> dataList = datum.getDataList();
            for (HotHomeEntity.DataListItem dataListItem : dataList) {
                if (dataListItem.getPlatformId() == null || dataListItem.getPlatformId() != 741){
                    continue;
                }
                homeDataMap.put(dataListItem.getName(),dataListItem.getId().toString());
            }
        }
        return homeDataMap;
    }
    public static List<HotHomeEntity.Category> getHomeDataList() throws IOException, InterruptedException {
        HttpClient httpClient = HttpSingleton.getInstance();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.x-metash.cn/h5/home/hot"))
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString("{\"page\":1,\"pageSize\":10,\"type\":\"hot\"}"))
                .build();

        // 构建本次请求返回结果
        HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
        ObjectMapper objectMapper = new ObjectMapper();
        HotHomeEntity homeResponse = objectMapper.readValue(response.body(), HotHomeEntity.class);
        return homeResponse.getData();
    }
    /**
     * 简易的邮箱发送功能
     * @param user
     */
    public void sendEmail(UserEntity user,String text){
        SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
        simpleMailMessage.setFrom(CommonConstant.EAMIL);
        simpleMailMessage.setTo(user.getEmail());
        simpleMailMessage.setSubject(text);
        simpleMailMessage.setText(text);
        mailSender.send(simpleMailMessage);
    }
    /**
     * 检查并处理任务执行结果 并用以退出循环
     *
     * @param futureList 任务列表
     */
    private void checkFutureResults(List<Future<String>> futureList, AtomicBoolean taskIsNeedContinue) {
        futureList.forEach(future -> {
            try {
                String result = future.get(CommonConstant.TIMEOUT_SECONDS, TimeUnit.SECONDS);
                System.out.println(result);
                if (result.contains(GoodsEnum.SUCCESS.getCode())) {
                    taskIsNeedContinue.set(false);
                }
            } catch (ExecutionException e) {
                System.out.println("处理任务执行异常--->"+e);;
            } catch (InterruptedException | TimeoutException e) {
                future.cancel(true);
                System.out.println("处理获取结果的超时或中断--->"+e);
            }
        });
        taskIsNeedContinue.get();
    }

    /**
     * 根据当前登录用户 构建业务对象
     * @param productId
     * @param currentUserConfig
     * @return
     */
    private static ThreadPool.ClockOrderTask buildOrderTaskByCurrentUser(Long productId, UserEntity currentUserConfig) {
        return ThreadPool.ClockOrderTask.builder()
                .bankCardNumber(currentUserConfig.getBankCardNumber())
                .addressId(currentUserConfig.getAddressId())
                .productId(productId)
                .passCode(currentUserConfig.getPassCode())
                .build();
    }

    /**
     * 处理获取的商品数据
     * @return 商品列表id
     */
    @Override
    public List<Long> getGoodsInfo(String archiveId,UserTaskInfo userTaskInfo, BigDecimal price) throws IOException, InterruptedException {

        // 获取商品列表信息
        GoodInfoNewEntity goodInfoEntity = getResponseDto(archiveId);
        // 添加任务的线程信息
        userTaskInfo.setTaskId(Thread.currentThread().getName());
        if (Objects.isNull(goodInfoEntity.getData().getGoodsArchiveList())){
            System.out.println(String.format("当前线程为:{%s},本次请求发送时间为{%s}，获取到的商品数量为空,不执行锁单操作~",Thread.currentThread().getName(),LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))));
            return Collections.emptyList();
        }
        // 按商品价格进行排序 映射id字段
        // 过滤商品状态为售罄的 过滤价格高于price的商品
        List<GoodInfoNewEntity.GoodsArchiveDto> unchangedGoodsList = goodInfoEntity.getData().getGoodsArchiveList();
        List<Long> productIds = unchangedGoodsList.stream()
                .filter(Objects::nonNull)
                .filter(goodsArchiveDto -> new BigDecimal(goodsArchiveDto.getGoodsPrice()).compareTo(price) < CommonConstant.ZERO)
                .filter(goodsArchiveDto -> CommonConstant.SOLD_OUT_STATUS != goodsArchiveDto.getSellStatus())
                .sorted(Comparator.comparing(GoodInfoNewEntity.GoodsArchiveDto::getGoodsPrice))
                .map(GoodInfoNewEntity.GoodsArchiveDto::getGoodsId)
                .collect(Collectors.toList());
        if (CollUtil.isEmpty(productIds)){
            System.out.println(String.format("当前线程为:{%s},本次请求发送时间为{%s}，获取到的商品数量为{%s},符合购买条件的商品数量为{%s},不执行锁单操作~",Thread.currentThread().getName(),LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),unchangedGoodsList.size(),productIds.size()));
        }
        return productIds;

    }

    /**
     * 锁单操作
     * 创建参数 发送请求
     * @param productId
     * @return
     */
    @Override
    public String clockXmOrder(Long productId,Integer addressId,String bankCardNumber,String passCode) throws IOException, InterruptedException {

        long startTime = System.currentTimeMillis();
        // 创建参数对象
//        JSONObject json = new JSONObject();
//        json.put("addressId", addressId);
//        json.put("goodsId", productId);
//        json.put("bankCardNumber", bankCardNumber);

        // 创建HttpRequest实例
        HttpClient httpClient1 = HttpSingleton.getInstance();
        HttpRequest request1 = HttpRequest.newBuilder()
                .uri(URI.create(UrlConstant.VERIFY))
                .header("Content-Type", "application/json")
                .header("Authorization", passCode)
                .POST(HttpRequest.BodyPublishers.ofString("{\"addressId\":"+addressId+",\"goodsId\":\""+productId+"\"}"))
                .build();
        HttpResponse<String> response1 = httpClient1.send(request1, HttpResponse.BodyHandlers.ofString());

        HttpClient httpClient = HttpSingleton.getInstance();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(UrlConstant.CLOCK_ORDER_URL_NEW))
                .header("Content-Type", "application/json")
                .header("Authorization", passCode)
                .POST(HttpRequest.BodyPublishers.ofString("{\n" +
                        "  \"addressId\": "+addressId+",\n" +
                        "  \"goodsId\": \""+productId+"\",\n" +
                        "  \"shortName\": \"SDKJ\",\n" +
                        "  \"devType\": 2\n" +
                        "}"))
                .build();

        // 构建本次请求返回结果
        HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
        JSONObject jsonObject = new JSONObject(response.body());
        Integer code = jsonObject.getInt("code");
        String msg = jsonObject.getString("msg");
        long methodCostTime = System.currentTimeMillis() - startTime;
        String resultString = String.format("当前线程为:{%s}方法执行时间为:{%s},耗时为:{%s},本次请求返回状态码为:%s,返回信息为---->%s",Thread.currentThread().getName(), LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), methodCostTime, code, msg);
        System.out.println(resultString);
        return resultString;

    }


    /**
     * 获取商品信息
     * 创建参数 发送请求
     * @param archiveId
     * @return
     * @throws IOException
     * @throws InterruptedException
     */
    private static GoodInfoNewEntity getResponseDto(String archiveId) throws IOException, InterruptedException {

        // 创建参数对象
//        JSONObject json = new JSONObject();
//        json.put("sellStatus", 1);
//        json.put("page", 1);
//        json.put("pageSize", 100);
//        json.put("archiveId", archiveId);
//        json.put("platformId", "894");

        // 创建httpClient实例对象
        HttpClient httpClient = HttpSingleton.getInstance();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(UrlConstant.GET_GOODS_URL))
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString("{\"archiveId\":\""+archiveId+"\",\"platformId\":\"741\",\"source\":\"1\",\"page\":1,\"pageSize\":20,\"sellStatus\":1,\"dealType\":\"\",\"goodsType\":\"\",\"isPayBond\":\"\",\"goodsNo\":null,\"maxPrize\":null,\"minPrize\":null}"))
                .build();
        HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.readValue(response.body(), GoodInfoNewEntity.class);

    }
}
